const fs = require('fs')
const path = require('path')

/**
 * 批量重命名和内容替换
 * @param {Object} config - 配置对象
 * @param {string} config.dir - 要处理的目录路径
 * @param {Object} config.mapping - 替换映射，key为要替换的内容，value为替换后的内容
 * @param {Array<string>} [config.ignore=[]] - 要忽略的文件或目录模式
 * @param {boolean} [config.recursive=true] - 是否递归处理子目录
 */
function batchRename(config) {
  let { dir } = config
  const { mapping, ignore = [], recursive = true } = config

  // 检查目录是否存在
  if (!fs.existsSync(dir)) {
    console.error(`目录 ${dir} 不存在`)
    return
  }

  // 读取目录内容
  const items = fs.readdirSync(dir)

  // 先处理目录本身
  const dirName = path.basename(dir)
  let newDirName = dirName
  Object.entries(mapping).forEach(([from, to]) => {
    if (dirName.includes(from)) {
      newDirName = newDirName.split(from).join(to)
    }
  })

  // 如果目录名需要更改
  if (newDirName !== dirName) {
    const parentDir = path.dirname(dir)
    const newDirPath = path.join(parentDir, newDirName)
    try {
      fs.renameSync(dir, newDirPath)
      console.log(`重命名目录: ${dirName} -> ${newDirName}`)
      dir = newDirPath // 更新目录路径
    } catch (err) {
      console.error(`重命名目录 ${dirName} 失败:`, err)
      return
    }
  }

  for (const item of items) {
    const fullPath = path.join(dir, item)
    const stat = fs.statSync(fullPath)

    // 检查是否需要忽略
    if (shouldIgnore(fullPath, ignore)) {
      continue
    }

    if (stat.isDirectory() && recursive) {
      // 递归处理子目录
      batchRename({
        dir: fullPath,
        mapping,
        ignore,
        recursive,
      })
    } else if (stat.isFile()) {
      // 处理文件
      processFile(fullPath, mapping)
    }
  }
}

/**
 * 判断文件或目录是否应该被忽略
 * @param {string} filePath - 文件或目录路径
 * @param {Array<string>} ignorePatterns - 忽略模式数组
 * @returns {boolean}
 */
function shouldIgnore(filePath, ignorePatterns) {
  const relativePath = path.basename(filePath)
  const fileExt = path.extname(relativePath)
  const dirName = path.basename(path.dirname(filePath))
  return ignorePatterns.some((pattern) => {
    // 如果模式是文件扩展名（以.开头），直接匹配扩展名
    if (pattern.startsWith('.')) {
      return fileExt === pattern
    }

    // 完整路径匹配
    if (pattern.startsWith('/')) {
      return filePath === pattern.slice(1)
    }

    // 完整文件名或目录名匹配
    return relativePath === pattern || dirName === pattern
  })
}

/**
 * 处理单个文件
 * @param {string} filePath - 文件路径
 * @param {Object} mapping - 替换映射
 */
function processFile(filePath, mapping) {
  const dirname = path.dirname(filePath)
  const filename = path.basename(filePath)
  let newFilename = filename

  // 替换文件名
  Object.entries(mapping).forEach(([from, to]) => {
    if (filename.includes(from)) {
      newFilename = filename.split(from).join(to)
    }
  })

  // 如果文件名需要更改
  if (newFilename !== filename) {
    const newPath = path.join(dirname, newFilename)
    try {
      fs.renameSync(filePath, newPath)
      console.log(`重命名文件: ${filename} -> ${newFilename}`)
      filePath = newPath // 更新文件路径以便后续内容替换
    } catch (err) {
      console.error(`重命名文件 ${filename} 失败:`, err)
      return
    }
  }

  // 替换文件内容
  try {
    let content = fs.readFileSync(filePath, 'utf8')
    let hasChanges = false

    Object.entries(mapping).forEach(([from, to]) => {
      if (content.includes(from)) {
        content = content.split(from).join(to)
        hasChanges = true
      }
    })

    if (hasChanges) {
      fs.writeFileSync(filePath, content, 'utf8')
      console.log(`更新文件内容: ${newFilename}`)
    }
  } catch (err) {
    console.error(`处理文件内容 ${newFilename} 失败:`, err)
  }
}

// 获取命令行参数
const targetDir = process.argv[2]

// 检查是否提供了目录参数
if (!targetDir) {
  console.error('请提供要处理的目录路径，例如：node app.js ./testFolder')
  process.exit(1)
}

// 将相对路径转换为绝对路径
const absolutePath = path.resolve(targetDir)

// 示例：替换映射
const mapping = {
  // 'abc': 'cba',  // 将'abc'替换为'cba'
  jiazhengrenyuan: 'yuesao',
  c1: 'b22',
}

// 示例：配置选项
const options = {
  ignore: ['node_modules', '.git', 'package-lock.json'], // 忽略这些文件和目录
  recursive: true, // 递归处理子目录
}

// 调用批量重命名函数
batchRename({
  dir: absolutePath,
  mapping,
  ignore: options.ignore,
  recursive: options.recursive,
})

// 运行示例
// 运行命令：node app.js ./testFolder
